unit database_skills;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, PairSplitter, ExtCtrls,
  StdCtrls, Buttons, Spin, Menus, database_base, itemselectorframeunit,
  skillitemadditionaldataframeunit, effectlistframeunit, iconselection, fpjson,
  LCLTranslator;

type

  { TDatabaseSkillsFrame }

  TDatabaseSkillsFrame = class(TDatabaseBaseFrame)
    AdditionalDataPanel: TPanel;
    AllowCriticalCheckBox: TCheckBox;
    AnimationComboBox: TComboBox;
    AnimationLabel: TLabel;
    CastsMenuItem: TMenuItem;
    CopyEffectMenuItem: TMenuItem;
    CostCommonLabel: TLabel;
    CutEffectMenuItem: TMenuItem;
    DamageElementComboBox: TComboBox;
    DamageElementLabel: TLabel;
    DamageGroupBox: TGroupBox;
    DamageTypeComboBox: TComboBox;
    DamageTypeLabel: TLabel;
    DeleteEffectMenuItem: TMenuItem;
    DescriptionLabel: TLabel;
    DescriptionMemo: TMemo;
    EditEffectMenuItem: TMenuItem;
    EffectListBox: TListBox;
    EffectsGroupBox: TGroupBox;
    EffectsNotesPairSplitter: TPairSplitter;
    EffectsPairSplitterSide: TPairSplitterSide;
    FormulaEdit: TEdit;
    FormulaLabel: TLabel;
    GeneralSettingsGroupBox: TGroupBox;
    HitTypeComboBox: TComboBox;
    HitTypeLabel: TLabel;
    IconIdLabel: TLabel;
    IconLabel: TLabel;
    IconSpeedButton: TSpeedButton;
    InvocationGroupBox: TGroupBox;
    ItemEffectListFrame: TEffectListFrame;
    SkillSelectorFrame: TItemSelectorFrame;
    MainContentPanel: TPanel;
    MainContentScrollBox: TScrollBox;
    Message1Edit: TEdit;
    Message1NameLabel: TLabel;
    Message2Edit: TEdit;
    MessagesGroupBox: TGroupBox;
    MpCostLabel: TLabel;
    MpCostSpinEdit: TSpinEdit;
    NameEdit: TEdit;
    NameLabel: TLabel;
    NotesGroupBox: TGroupBox;
    NotesMemo: TMemo;
    NotesPairSplitterSide: TPairSplitterSide;
    OccasionComboBox: TComboBox;
    OccasionLabel: TLabel;
    PasteEffectMenuItem: TMenuItem;
    RepeatLabel: TLabel;
    RepeatSpinEdit: TSpinEdit;
    ScopeComboBox: TComboBox;
    ScopeLabel: TLabel;
    SkillAdditionalDataFrame: TSkillItemAdditionalDataFrame;
    SkillTypeComboBox: TComboBox;
    SkillTypeLabel: TLabel;
    SpeedLabel: TLabel;
    SpeedSpinEdit: TSpinEdit;
    SelectorContentSplitter: TSplitter;
    SuccessLabel: TLabel;
    SuccessPercentLabel: TLabel;
    SuccessSpinEdit: TSpinEdit;
    TpCostLabel: TLabel;
    TpCostSpinEdit: TSpinEdit;
    TpGainLabel: TLabel;
    TpGainSpinEdit: TSpinEdit;
    VarianceLabel: TLabel;
    VariancePercentLabel: TLabel;
    VarianceSpinEdit: TSpinEdit;
    WeaponTypesGroupBox: TGroupBox;
    WType1ComboBox: TComboBox;
    WType2ComboBox: TComboBox;
    procedure AnimationComboBoxChange(Sender: TObject);
    procedure DescriptionMemoChange(Sender: TObject);
    procedure HitTypeComboBoxChange(Sender: TObject);
    procedure IconSpeedButtonClick(Sender: TObject);
    procedure LoadSkillData(NewId: Integer);
    procedure LoadGeneralSettings(Skill: TJSONObject);
    procedure LoadIcon(Skill: TJSONObject);
    procedure LoadInvocationData(Skill: TJSONObject);
    procedure LoadMessages(Skill: TJSONObject);
    procedure LoadWeaponTypes(Skill: TJSONObject);
    procedure FillSkillTypes;
    procedure FillWeaponTypes;
    procedure FillAnimations;
    function GetSelectedSkill: TJSONObject;

    procedure Init; override;
    procedure MessageEditChange(Sender: TObject);
    procedure MpCostSpinEditChange(Sender: TObject);
    procedure NameEditChange(Sender: TObject);
    procedure OccasionComboBoxChange(Sender: TObject);
    procedure RepeatSpinEditChange(Sender: TObject);
    procedure ScopeComboBoxChange(Sender: TObject);
    procedure SkillTypeComboBoxChange(Sender: TObject);
    procedure SpeedSpinEditChange(Sender: TObject);
    procedure SuccessSpinEditChange(Sender: TObject);
    procedure TpCostSpinEditChange(Sender: TObject);
    procedure TpGainSpinEditChange(Sender: TObject);
    procedure WTypeComboBoxChange(Sender: TObject);
  private
    IsLoading: Boolean;
    SelectedId: Integer;
    procedure ResizeMemo;
  public

  end;

resourcestring
  SkillsHeader = 'Skills';
  SkillTypeNone = 'No skill type';

implementation

uses
  gamefont, globals, comboboxhelper, constants;

procedure TDatabaseSkillsFrame.LoadSkillData(NewId: Integer);
var
  Skill: TJSONObject;
begin
  IsLoading := True;
  SelectedId := NewId;

  Skill := GetSelectedSkill;

  LoadGeneralSettings(Skill);
  LoadInvocationData(Skill);
  LoadMessages(Skill);
  LoadWeaponTypes(Skill);
  SkillAdditionalDataFrame.SetItem(NewId);

  //TODO

  IsLoading := False;
end;

procedure TDatabaseSkillsFrame.LoadGeneralSettings(Skill: TJSONObject);
var
  SkillName: String = '';
  SkillType: Integer = 0;
  MpCost: Integer = 0;
  TpCost: Integer = 0;
  Scope: Integer = 0;
  Occasion: Integer = 0;
  Description: String = '';
  SkillNameJson, DescriptionJson: TJSONString;
  SkillTypeJson, ScopeJson, OccasionJson, MpCostJson, TpCostJson: TJSONNumber;
begin
  if (Skill <> nil) and Skill.Find('name', SkillNameJson) then
    SkillName := SkillNameJson.AsString;
  NameEdit.Text := SkillName;

  LoadIcon(Skill);

  if (Skill <> nil) and Skill.Find('description', DescriptionJson) then
    Description := DescriptionJson.AsString;
  DescriptionMemo.Text := Description;

  if (Skill <> nil) and Skill.Find('stypeId', SkillTypeJson) then
    SkillType := SkillTypeJson.AsInteger;
  SkillTypeComboBox.ItemIndex := SkillType;

  if (Skill <> nil) and Skill.Find('mpCost', MpCostJson) then
    MpCost := MpCostJson.AsInteger;
  MpCostSpinEdit.Value := MpCost;

  if (Skill <> nil) and Skill.Find('tpCost', TpCostJson) then
    TpCost := TpCostJson.AsInteger;
  TpCostSpinEdit.Value := TpCost;

  if (Skill <> nil) and Skill.Find('scope', ScopeJson) then
    Scope := ScopeJson.AsInteger;
  ScopeComboBox.ItemIndex := Scope;

  if (Skill <> nil) and Skill.Find('occasion', OccasionJson) then
    Occasion := OccasionJson.AsInteger;
  OccasionComboBox.ItemIndex := Occasion;
end;

procedure TDatabaseSkillsFrame.LoadIcon(Skill: TJSONObject);
var
  IconId: Integer = 0;
  IconIdJson: TJSONNumber;
  IconBitmap: TBitmap;
begin
  if (Skill <> nil) and Skill.Find('iconIndex', IconIdJson) then
    IconId := IconIdJson.AsInteger;

  IconIdLabel.Caption := IntToStr(IconId);
  if IconId <> 0 then begin
    IconBitmap := Game.GetIcon(IconId);
    IconSpeedButton.Glyph.Assign(IconBitmap);
    IconBitmap.Free;
  end else
    IconSpeedButton.Glyph.Clear;
end;

procedure TDatabaseSkillsFrame.LoadInvocationData(Skill: TJSONObject);
var
  Speed: Integer = 0;
  SuccessRate: Integer = 0;
  Repeats: Integer = 0;
  TpGain: Integer = 0;
  HitType: Integer = 0;
  AnimationId: Integer = -1;
  SpeedJson, SuccessRateJson, RepeatsJson, TpGainJson, HitTypeJson,
    AnimationIdJson: TJSONNumber;
begin
  if (Skill <> nil) and Skill.Find('speed', SpeedJson) then
    Speed := SpeedJson.AsInteger;
  SpeedSpinEdit.Value := Speed;

  if (Skill <> nil) and Skill.Find('successRate', SuccessRateJson) then
    SuccessRate := SuccessRateJson.AsInteger;
  SuccessSpinEdit.Value := SuccessRate;

  if (Skill <> nil) and Skill.Find('repeats', RepeatsJson) then
    Repeats := RepeatsJson.AsInteger;
  RepeatSpinEdit.Value := Repeats;

  if (Skill <> nil) and Skill.Find('tpGain', TpGainJson) then
    TpGain := TpGainJson.AsInteger;
  TpGainSpinEdit.Value := TpGain;

  if (Skill <> nil) and Skill.Find('hitType', HitTypeJson) then
    HitType := HitTypeJson.AsInteger;
  HitTypeComboBox.ItemIndex := HitType;

  if (Skill <> nil) and Skill.Find('animationId', AnimationIdJson) then
    AnimationId := AnimationIdJson.AsInteger;
  AnimationComboBox.ItemIndex := AnimationId + 1;
end;

procedure TDatabaseSkillsFrame.LoadMessages(Skill: TJSONObject);
var
  Msg1: String = '';
  Msg2: String = '';
  Msg1Json, Msg2Json: TJSONString;
begin
  if (Skill <> nil) and Skill.Find('message1', Msg1Json) then
    Msg1 := Msg1Json.AsString;
  Message1Edit.Text := Msg1;

  if (Skill <> nil) and Skill.Find('message2', Msg2Json) then
    Msg2 := Msg2Json.AsString;
  Message2Edit.Text := Msg2;
end;

procedure TDatabaseSkillsFrame.LoadWeaponTypes(Skill: TJSONObject);
var
  WType1: Integer = 0;
  WType2: Integer = 0;
  WType1Json, WType2Json: TJSONNumber;
begin
  if (Skill <> nil) and Skill.Find('requiredWtypeId1', WType1Json) then
    WType1 := WType1Json.AsInteger;
  WType1ComboBox.ItemIndex := WType1;

  if (Skill <> nil) and Skill.Find('requiredWtypeId2', WType2Json) then
    WType2 := WType2Json.AsInteger;
  WType2ComboBox.ItemIndex := WType2;
end;

procedure TDatabaseSkillsFrame.FillSkillTypes;
var
  I: Integer;
  SkillTypes: TJSONArray;
begin
  if (Db = nil) or (Db.System = nil) then
    Exit;

  if not Db.System.Find('skillTypes', SkillTypes) then
    Exit;

  with SkillTypeComboBox.Items do begin
    BeginUpdate;
    Clear;
    Append(SkillTypeNone);
    for I := 1 to SkillTypes.Count -1 do begin
      Append(Db.GetSkillTypeName(I));
    end;
    EndUpdate;
  end;
end;

procedure TDatabaseSkillsFrame.FillWeaponTypes;
var
  I: Integer;
  WeaponTypes: TJSONArray;
begin
  if (Db = nil) or (Db.System = nil) then
    Exit;

  if not Db.System.Find('weaponTypes', WeaponTypes) then
    Exit;

  with WType1ComboBox.Items do begin
    BeginUpdate;
    Clear;
    Append('');
    for I := 1 to WeaponTypes.Count -1 do begin
      Append(Db.GetWeaponTypeName(I));
    end;
    EndUpdate;
  end;
  WType2ComboBox.Items.Assign(WType1ComboBox.Items);
end;

procedure TDatabaseSkillsFrame.FillAnimations;
var
  I: Integer;
begin
  if (Db = nil) or (Db.Animations = nil) then
    Exit;

  with AnimationComboBox.items do begin
    BeginUpdate;
    Clear;
    Append(AnimationNormalAttack);
    Append(AnimationNone);
    for I := 1 to Db.Animations.Count -1 do begin
      Append(Db.GetAnimName(I));
    end;
    EndUpdate;
  end;
end;

function TDatabaseSkillsFrame.GetSelectedSkill: TJSONObject;
begin
  if (SelectedId >= 1) and (SelectedId < Db.Skills.Count) then
    GetSelectedSkill := Db.Skills[SelectedId] as TJSONObject
  else
    GetSelectedSkill := nil;
end;

procedure TDatabaseSkillsFrame.HitTypeComboBoxChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['hitType'] := HitTypeComboBox.ItemIndex;
end;

procedure TDatabaseSkillsFrame.IconSpeedButtonClick(Sender: TObject);
var
  Skill: TJSONObject;
  IconIndex: Integer = 0;
  IconIndexJson: TJSONNumber;
begin
  Skill := GetSelectedSkill;
  if (Skill <> nil) and Skill.Find('iconIndex', IconIndexJson) then
    IconIndex := IconIndexJson.AsInteger;

  if IconSelectionForm.ShowIconSelection(IconIndex) then begin
    Skill.Integers['iconIndex'] := IconSelectionForm.SelectedIconId;
    LoadIcon(Skill);
  end;
end;

procedure TDatabaseSkillsFrame.DescriptionMemoChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Strings['description'] := DescriptionMemo.Text;
end;

procedure TDatabaseSkillsFrame.AnimationComboBoxChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['animationId'] := AnimationComboBox.ItemIndex - 1;
end;

procedure TDatabaseSkillsFrame.Init;
begin
  IsLoading := True;
  SkillSelectorFrame.SetData(Db.Skills, @Db.ResizeSkills, @LoadSkillData);
  SkillSelectorFrame.Title := SkillsHeader;
  SkillSelectorFrame.JsonDataType := 'application/rpgmv-skills';
  SkillSelectorFrame.CreateElementCallback := @Db.CreateEmptySkill;

  SkillAdditionalDataFrame.SetDatabase(Db, siadtSkill);
  FillSkillTypes;
  FillAnimations;
  FillWeaponTypes;
  FillScopeComboBox(ScopeComboBox);
  FillScopeComboBox(ScopeComboBox);
  FillOccasionComboBox(OccasionComboBox);
  FillHitTypeComboBox(HitTypeComboBox);

  ResizeMemo;

  LoadSkillData(1);
end;

procedure TDatabaseSkillsFrame.MessageEditChange(Sender: TObject);
var
  Skill: TJSONObject;
  Edit: TEdit;
begin
  Edit := Sender as TEdit;
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Strings['message' + IntToStr(Edit.Tag)] := Edit.Text;
end;

procedure TDatabaseSkillsFrame.MpCostSpinEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['mpCost'] := MpCostSpinEdit.Value;
end;

procedure TDatabaseSkillsFrame.NameEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then begin
    Skill.Strings['name'] := NameEdit.Text;
    SkillSelectorFrame.RefreshSelectedName;
  end;
end;

procedure TDatabaseSkillsFrame.OccasionComboBoxChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['occasion'] := OccasionComboBox.ItemIndex;
end;

procedure TDatabaseSkillsFrame.RepeatSpinEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['repeats'] := RepeatSpinEdit.Value;
end;

procedure TDatabaseSkillsFrame.ScopeComboBoxChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['scope'] := ScopeComboBox.ItemIndex;
end;

procedure TDatabaseSkillsFrame.SkillTypeComboBoxChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['stypeId'] := SkillTypeComboBox.ItemIndex;
end;

procedure TDatabaseSkillsFrame.SpeedSpinEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['speed'] := SpeedSpinEdit.Value;
end;

procedure TDatabaseSkillsFrame.SuccessSpinEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['successRate'] := SuccessSpinEdit.Value;
end;

procedure TDatabaseSkillsFrame.TpCostSpinEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['tpCost'] := TpCostSpinEdit.Value;
end;

procedure TDatabaseSkillsFrame.TpGainSpinEditChange(Sender: TObject);
var
  Skill: TJSONObject;
begin
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['tpGain'] := TpGainSpinEdit.Value;
end;

procedure TDatabaseSkillsFrame.WTypeComboBoxChange(Sender: TObject);
var
  Skill: TJSONObject;
  Box: TComboBox;
begin
  Box := Sender as TComboBox;
  Skill := GetSelectedSkill;
  if Skill <> nil then
    Skill.Integers['requiredWtypeId' + IntToStr(Box.Tag)] := Box.ItemIndex;
end;

procedure TDatabaseSkillsFrame.ResizeMemo;
begin
  DescriptionMemo.Font.BeginUpdate;
  DescriptionMemo.Font.Name := GetMonospacedFontName;
  DescriptionMemo.Font.Size := GetMonospacedFontSize;
  DescriptionMemo.Font.EndUpdate;
  ResizeMemoForFont(DescriptionMemo, 55, 2);
end;

{$R *.lfm}

end.

